package cn.barudisshu.scheduler;

import org.joda.time.LocalDate;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

/**
 * @author barudisshu
 */
public class Scheduler {

    private List<JobDetail> jobList = new ArrayList<>();
    private TreeSet<Trigger> triggerList = new TreeSet<>();
    private final Object lockObj = new Object();
    private SchedulerThread thread = new SchedulerThread();
    private boolean shutDown = false;

    public void schedulerJob(JobDetail jobDetail, Trigger trigger) {
        synchronized (lockObj) {
            jobList.add(jobDetail);
            trigger.setJobKey(jobDetail.getJobName());
            triggerList.add(trigger);
        }
    }

    public void start() {
        System.out.println("########## run scheduler at: " + LocalDate.now() + " ###########");
        thread.start();
    }

    public void halt() {
        thread.halt();
    }
    private class SchedulerThread extends Thread {

        @Override
        public void run() {
            while (!shutDown) {
                synchronized (lockObj) {
                    try {
                        final Trigger trigger = triggerList.pollFirst();
                        if (trigger == null) {
                            lockObj.wait(100);
                            continue;
                        }
                        long curr = System.currentTimeMillis();
                        long nextTime = trigger.getNextFireTime();

                        while (nextTime > curr && !shutDown) {
                            curr = System.currentTimeMillis();
                            if (nextTime > curr + 1)
                                lockObj.wait(nextTime - curr);
                            if (!shutDown) {
                                int index = jobList.indexOf(new JobDetail(trigger.getJobKey(),null));
                                JobDetail jobDetail = jobList.get(index);
                                Job job = jobDetail.getClazz().newInstance();
                                job.execute(jobDetail.getJobData());
                                trigger.resert();
                                nextTime = trigger.getNextFireTime();
                                if (nextTime != -1) {
                                    triggerList.add(trigger);
                                } else {
                                    break;
                                }
                            }
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public void halt() {
            synchronized (lockObj) {
                shutDown = true;
                lockObj.notifyAll();
            }
        }
    }

}
